package com.lgx.authorize.util;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.text.ParseException;

import org.springframework.jdbc.core.RowMapper;

/**
 * this support mapping redis
 * @author pengdeyi (king)
 *
 * @param <T>
 */
public class RowMapperEffective<T> implements RowMapper<T> {

	/**
	 * this parameter is construct class for mapping
	 */
	private Class<T> tType;
	
	public RowMapperEffective(Class<T> tType) {
		this.tType = tType;
	}
	
	public Class<T> gettType() {
		return tType;
	}

	public void settType(Class<T> tType) {
		this.tType = tType;
	}

	/*
	 * (non-Javadoc)
	 * @see org.springframework.jdbc.core.RowMapper#mapRow(java.sql.ResultSet, int)
	 */
	@Override
	public T mapRow(ResultSet rs, int rownum) throws SQLException {
		T t = null;
		try {
			//use reflect to install object
			t = tType.newInstance();
			Field[] fields = tType.getDeclaredFields();
			
			if(fields!=null&&fields.length!=0){
				
				for(Field field:fields){
					//condition the parameters is used in mapper.
					if(field.getAnnotation(LgxField.class)!=null&&
							field.getAnnotation(LgxField.class).required()){
						
						String fieldName = field.getName();
						//get method used type.
						String fieldType = field.getGenericType().toString();
						
						if(fieldType.contains(".")){
							
							fieldType = fieldType.substring(fieldType.lastIndexOf(".") + 1);
						
						}else{
						
							fieldType = fieldType.substring(0,1).toUpperCase()+fieldType.substring(1);
						
						}
						
						String setMethod = "set"+fieldName.substring(0,1).
								toUpperCase()+fieldName.substring(1);//this used in class T
						
						System.out.println(field.getAnnotation(LgxField.class).name());
						//now don't case this  not case lgxField class
//						if(StringUtils.isNotBlank(field.getAnnotation(LgxField.class).name())){
//							
//							Object _result = rs.getClass().getMethod("get"+fieldType,String.class).
//									invoke(rs,field.getAnnotation(LgxField.class).name());
//							
//							Method method = tType.getMethod(setMethod, classTypeCharge(_result.getClass()));
//							
//							method.invoke(t, _result);
//						}else{
							Object _result = null;
							if(fieldType.equals("Date")){
								fieldType = "String";
								_result = rs.getClass().getMethod("get"+fieldType,String.class).invoke(rs,fieldName);
								_result = DateCharger.chargeDate((String) _result);
							}else{
								_result = rs.getClass().getMethod("get"+fieldType,String.class).invoke(rs,fieldName);
							}
							
							//condition null point case object type;
							if(_result!=null){
							
								Method method = tType.getMethod(setMethod, classTypeCharge(_result.getClass()));
							
								method.invoke(t, _result);
							}
//						}
					}
				}
			}
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			e.printStackTrace();
		} catch (ParseException e) {
			e.printStackTrace();
		}
		return t;
	}
	
	/**
	 * class change
	 * @param clazz
	 * @return
	 */
	@SuppressWarnings("rawtypes")
	private Class classTypeCharge(Class clazz){
		
		if(clazz.equals(Integer.class)){
			return int.class;
		}
		
		if(clazz.equals(Long.class)){
			return long.class;
		}
		
		if(clazz.equals(Double.class)){
			return double.class;
		}
		
		if(clazz.equals(Float.class)){
			return float.class;
		}
		
		if(clazz.equals(Short.class)){
			return short.class;
		}
		
		if(clazz.equals(Character.class)){
			return char.class;
		}
		
		if(clazz.equals(Boolean.class)){
			return boolean.class;
		}
		
		
		return clazz;
	}
	
}
